package com.neolix.watch.view;

import android.animation.Animator;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.LinearLayout;

import com.neolix.watch.R;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static com.neolix.watch.NeolixApplication.getInstance;

public class TestSurfaceView extends LinearLayout {
    private final Context context;
    private List<Integer> stepsList = new ArrayList<Integer>();
    private String TAG = TestSurfaceView.class.getSimpleName();
    private SurfaceView surfaceView;
    private SurfaceHolder holder;
    private ValueAnimator valueAnimator;
    private float width;
    private float height;
    private List<PointF> pointList;
    private PointF lastPoint, currentPoint;
    private Paint linePaint;
    private Paint circlePaint;
    private int currentIndex;

    public TestSurfaceView(Context context) {
        super(context);
        this.context = context;
        initUi();
    }

    public TestSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        initUi();
    }

    public TestSurfaceView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.context = context;
        initUi();
    }

    private void initUi() {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.view_surface, this);

        surfaceView = (SurfaceView) findViewById(R.id.surface_view);

        initPaint();
        initHolder();
    }

    private void resetAnimator(PointF startPoint, PointF endPoint) {
        valueAnimator = ValueAnimator.ofObject(new BezierEvaluator(), startPoint, endPoint);
        valueAnimator.setDuration(500);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //TODO: 画图
//                currentPoint = (PointF) animation.getAnimatedValue();
//                Path path = new Path();
//                path.moveTo(lastPoint.x, lastPoint.y);
//                path.lineTo(currentPoint.x, currentPoint.y);
////
//                Canvas canvas = holder.lockCanvas(new Rect((int) (lastPoint.x + 0.5), (int) ((currentPoint.y - lastPoint.y > 0 ? lastPoint.y : currentPoint.y) + 0.5),
//                        (int) (currentPoint.x + 0.5), (int) ((currentPoint.y - lastPoint.y > 0 ? currentPoint.y : lastPoint.y) + 0.5)));
//
//
////                Canvas canvas = holder.lockCanvas();
//                canvas.drawPath(path, linePaint);
//                holder.unlockCanvasAndPost(canvas);
//                lastPoint = currentPoint;
            }
        });

        valueAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {
                Shader mShader = new RadialGradient(pointList.get(currentIndex).x, pointList.get(currentIndex).y, 5, new int[]{getInstance().getResources().getColor(R.color.curve_color),
                        getInstance().getResources().getColor(R.color.text_color_yellow)}, null, Shader.TileMode.REPEAT);
                circlePaint.setShader(mShader);

                Canvas canvas = holder.lockCanvas(new Rect((int) pointList.get(currentIndex).x - 5, (int) pointList.get(currentIndex).y - 5,
                        (int) pointList.get(currentIndex).x + 5, (int) pointList.get(currentIndex).y + 5));

                canvas.drawCircle(pointList.get(currentIndex).x, pointList.get(currentIndex).y, 10, circlePaint);
                holder.unlockCanvasAndPost(canvas);
            }

            @Override
            public void onAnimationEnd(Animator animator) {
                Path path = new Path();
                lastPoint = pointList.get(currentIndex);
                currentPoint = pointList.get(currentIndex + 1);

                path.moveTo(pointList.get(currentIndex).x, pointList.get(currentIndex).y);
                path.lineTo(pointList.get(currentIndex + 1).x, pointList.get(currentIndex + 1).y);

                Canvas canvas = holder.lockCanvas(new Rect((int) (lastPoint.x + 0.5), (int) ((currentPoint.y - lastPoint.y > 0 ? lastPoint.y : currentPoint.y) + 0.5),
                        (int) (currentPoint.x + 0.5), (int) ((currentPoint.y - lastPoint.y > 0 ? currentPoint.y : lastPoint.y) + 0.5)));
//
//
////                Canvas canvas = holder.lockCanvas();
                canvas.drawPath(path, linePaint);
                holder.unlockCanvasAndPost(canvas);
                currentIndex++;
                if (currentIndex < pointList.size() - 1)
                    startAnimation();
                Log.i(TAG, "动画结束");
            }

            @Override
            public void onAnimationCancel(Animator animator) {

            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });
        valueAnimator.setRepeatCount(0);
        valueAnimator.setRepeatMode(ValueAnimator.INFINITE);
    }

    private void initHolder() {
        holder = surfaceView.getHolder();
        holder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder surfaceHolder) {
                drawBack(surfaceHolder);
                postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        currentIndex = 0;
                        startAnimation();
                    }
                }, 2000);
            }

            @Override
            public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
                drawBack(surfaceHolder);
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder surfaceHolder) {

            }
        });
    }

    private void initPaint() {
        circlePaint = new Paint();
        circlePaint.setColor(getInstance().getResources().getColor(R.color.text_color_yellow));
        circlePaint.setAntiAlias(true);
        circlePaint.setStrokeWidth(1);
        circlePaint.setStyle(Paint.Style.FILL);


        linePaint = new Paint();
        linePaint.setColor(getInstance().getResources().getColor(R.color.curve_color));
        linePaint.setAntiAlias(true);
        linePaint.setStrokeWidth(5);
        linePaint.setStyle(Paint.Style.STROKE);
    }


    public void setData(List<Integer> stepsList) {
        this.stepsList = stepsList;
//        invalidate();
        int height = getHeight();
        int width = getWidth();

        Log.i(TAG, "height:" + height + "    width:" + width);

        //Calculation width info
        int count = this.stepsList.size();
        int eachWidth = width / count;
        int startValue = eachWidth / 2;
        int padding = 10;

        //Calculation height info
        Integer max = Collections.max(stepsList);
        Integer min = Collections.min(stepsList);

        float eachHeight = (float) height / (max - min + 1);

        //TODO if max-min=0
        //Calculation path
        float yValue;
        float xValue;

        pointList = new ArrayList<PointF>();
        PointF po;
        for (int i = 0; i < count; i++) {
            xValue = startValue + (i) * eachWidth;

            if (max - min == 0 && max != 0)
                // 如果每个点都一样则画在最上面
                yValue = padding;
            else if (max - min == 0 && max == 0) {
                // 如果每个点都一样则画在最下面
                yValue = height - padding;
            } else {
                yValue = height - ((stepsList.get(i) - min) * eachHeight);
                if (stepsList.get(i).equals(max))
                    //最大 则和TOP留出padding 不然 画笔比较粗时，有部分看不见
                    yValue += padding;
                else if (stepsList.get(i).equals(min))
                    //最小 则和BOTTOM留出padding 不然 画笔比较粗时，有部分看不见
                    yValue -= padding;
            }

            po = new PointF(xValue, yValue);
            pointList.add(po);
        }
    }

    private void drawBack(SurfaceHolder holder) {
        Canvas canvas = holder.lockCanvas();
        //绘制白色背景
//        canvas.drawColor(getInstance().getResources().getColor(R.color.main_activity_menu));
        canvas.drawColor(Color.WHITE);

        //绘制坐标轴
        holder.unlockCanvasAndPost(canvas);
        holder.lockCanvas(new Rect(0, 0, 0, 0));
        holder.unlockCanvasAndPost(canvas);
    }

    private void startAnimation() {
        lastPoint = pointList.get(currentIndex);
        width = pointList.get(currentIndex + 1).x - pointList.get(currentIndex).x;
        height = Math.abs(pointList.get(currentIndex + 1).y - pointList.get(currentIndex).y);
        resetAnimator(lastPoint, pointList.get(currentIndex + 1));
        valueAnimator.start();
    }

    class BezierEvaluator implements TypeEvaluator<PointF> {

        @Override
        public PointF evaluate(float fraction, PointF startValue,
                               PointF endValue) {
            final float t = fraction;
            float oneMinusT = 1.0f - t;
            PointF point = new PointF();

            PointF point0 = (PointF) startValue;

            PointF point1 = new PointF();
            point1.set(width, 0);

            PointF point2 = new PointF();
            point2.set(0, height);

            PointF point3 = (PointF) endValue;

            point.x = oneMinusT * oneMinusT * oneMinusT * (point0.x)
                    + 3 * oneMinusT * oneMinusT * t * (point1.x)
                    + 3 * oneMinusT * t * t * (point2.x)
                    + t * t * t * (point3.x);

            point.y = oneMinusT * oneMinusT * oneMinusT * (point0.y)
                    + 3 * oneMinusT * oneMinusT * t * (point1.y)
                    + 3 * oneMinusT * t * t * (point2.y)
                    + t * t * t * (point3.y);
            return point;
        }
    }
}
